home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xconq / do.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  31KB  |  1,239 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. #pragma comment(exestr, "@(#) do.c 12.1 95/05/09 ")
  6.  
  7. /* RCS $Header: do.c,v 1.2 88/07/17 17:08:59 shebs Exp $ */
  8.  
  9. /* This file contains almost all command functions. */
  10. /* Help commands are in a separate file. */
  11.  
  12. #include "config.h"
  13. #include "misc.h"
  14. #include "dir.h"
  15. #include "period.h"
  16. #include "side.h"
  17. #include "unit.h"
  18. #include "map.h"
  19. #include "global.h"
  20.  
  21. extern bool delaymove;
  22.  
  23. char *grok_string();
  24.  
  25. bool reconfig;          /* true when an option needs screen reconfigured */
  26. bool remap;             /* true when only main map needs redrawing */
  27. bool reinfo;            /* true when only info display needs redrawing */
  28. bool tmparea = TRUE;    /* true for area painting, false for bar painting */
  29.  
  30. /* Things will be totally scrogged if two human players in build mode... */
  31.  
  32. int tmpterr = 0;    /* temporary terrain type for area operation */
  33. int tmpdist = 0;        /* temporary argument for painting */
  34. int tmpflag;        /* temporary int for area operation */
  35.  
  36. /* Move in given direction a given distance - used for both single and */
  37. /* automatic multiple moves. */
  38.  
  39. do_dir(side, dir, n)
  40. Side *side;
  41. int dir, n;
  42. {
  43.     if (side->teach) {
  44.     cache_movedir(side, dir, n);
  45.     } else {
  46.     switch (side->mode) {
  47.     case MOVE:
  48.         if (side->curunit != NULL) order_movedir(side->curunit, dir, n);
  49.         break;
  50.     case SURVEY:
  51.         move_survey(side,
  52.             wrap(side->curx + n*dirx[dir]),
  53.             side->cury + n*diry[dir]);
  54.         break;
  55.     default:
  56.         case_panic("mode", side->mode);
  57.     }
  58.     }
  59. }
  60.  
  61. /* Wake *everything* (that's ours) within the given radius.  Two commands */
  62. /* actually; lowercase is transports only, uppercase is everybody. */
  63.  
  64. do_wakeup(side, n)
  65. Side *side;
  66. int n;
  67. {
  68.     if (side->teach) {
  69.     cache_awake(side, 1);
  70.     } else {
  71.     wakeup_area(side, n, TRUE);
  72.     side->info_change = TRUE;
  73.     }
  74. }
  75.  
  76. /* Wake up only the main/current unit in a hex. */
  77.  
  78. do_wakemain(side, n)
  79. Side *side;
  80. int n;
  81. {
  82.     if (side->teach) {
  83.     cache_awake(side, 1);
  84.     } else {
  85.     wakeup_area(side, n, FALSE);
  86.     side->info_change = TRUE;
  87.     }
  88. }
  89.  
  90. /* The area wakeup. */
  91.  
  92. wake_at(x, y)
  93. int x, y;
  94. {
  95.     Unit *unit = unit_at(x, y);
  96.  
  97.     if (unit != NULL && (unit->side == tmpside || Build))
  98.     wake_unit(unit, tmpflag);
  99. }
  100.  
  101. wakeup_area(side, n, occs)
  102. Side *side;
  103. int n, occs;
  104. {
  105.     tmpside = side;
  106.     tmpflag = occs;
  107.     apply_to_area(side->curx, side->cury, n, wake_at);
  108. }
  109.  
  110. /* Put unit to sleep for a while.  If we sleep it next to something that */
  111. /* might wake it up, then adjust flags so it won't wake up on next turn. */
  112.  
  113. do_sentry(side, unit, n)
  114. Side *side;
  115. Unit *unit;
  116. int n;
  117. {
  118.     if (side->teach) {
  119.     cache_sentry(side, n);
  120.     } else {
  121.     order_sentry(unit, n);
  122.     if (n > 1 && adj_enemy(unit))
  123.         unit->orders.flags &= ~(ENEMYWAKE|NEUTRALWAKE);
  124.     side->info_change = TRUE;
  125.     }
  126. }
  127.  
  128. /* Don't move for remainder of turn, but be awake next turn.  This also */
  129. /* hooks into terrain painting, since the space bar is big and convenient. */
  130.  
  131. do_sit(side, n)
  132. Side *side;
  133. int n;
  134. {
  135.     if (side->mode == SURVEY && Build) {
  136.     paint_terrain(side);
  137.     } else if (side->curunit != NULL) {
  138.     do_sentry(side, side->curunit, 1);
  139.     side->info_change = TRUE;
  140.     } else {
  141.     cmd_error(side, "No unit to operate on here!");
  142.     }
  143. }
  144.  
  145. /* Set unit to move to a given location.  */
  146.  
  147. x_moveto(side)
  148. Side *side;
  149. {
  150.     if (grok_position(side)) {
  151.     if (side->teach) {
  152.         cache_moveto(side, side->reqposx, side->reqposy);
  153.     } else if (Build) {
  154.         leave_hex(side->requnit);
  155.         occupy_hex(side->requnit, side->reqposx, side->reqposy);
  156.         make_current(side, side->requnit);
  157.         all_see_hex(side->curx, side->cury);
  158.     } else {
  159.         order_moveto(side->requnit, side->reqposx, side->reqposy);
  160.         side->info_change = TRUE;
  161.     }
  162.     restore_cur(side);
  163.     } else {
  164.     request_input(side, side->requnit, x_moveto);
  165.     }
  166. }
  167.  
  168. /* The command proper. */
  169.  
  170. do_moveto(side, unit, n)
  171. Side *side;
  172. Unit *unit;
  173. int n;
  174. {
  175.     ask_position(side, "Move to where?");
  176.     request_input(side, unit, x_moveto);
  177.     side->reqposx = side->curx;  side->reqposy = side->cury;
  178. }
  179.  
  180. /* Auxiliary stuff used when searching for place to return to.  Note that */
  181. /* a good refueling spot will be woken up, so it won't get too far away */
  182. /* before unit has a chance to get there. */
  183. /* Won't find refueling places inside other units, sigh. */
  184.  
  185. refuel_here(x, y)
  186. int x, y;
  187. {
  188.     Unit *unit = unit_at(x, y);
  189.  
  190.     if (unit != NULL && unit->side == tmpside && can_carry(unit, tmpunit)) {
  191.     wake_unit(unit, FALSE);
  192.     return TRUE;
  193.     }
  194.     return FALSE;
  195. }
  196.  
  197. /* Search for a friendly refueler within range and set course for it.  */
  198. /* Warn player and refuse to move if nothing close enough. */
  199.  
  200. do_return(side, unit, n)
  201. Side *side;
  202. Unit *unit;
  203. int n;
  204. {
  205.     int x, y, u = unit->type, r, range = max(world.width, world.height);
  206.  
  207.     for_all_resource_types(r) {
  208.     if (utypes[u].tomove[r] > 0) {
  209.         range = min(range, unit->supply[r] / utypes[u].tomove[r]);
  210.     }
  211.     }
  212.     tmpside = side;
  213.     tmpunit = unit;
  214.     if (search_area(unit->x, unit->y, range, refuel_here, &x, &y)) {
  215.     if (unit->x != x || unit->y != y) {
  216.         order_moveto(unit, x, y);
  217.         unit->orders.flags = SHORTESTPATH;
  218.         side->info_change = TRUE;
  219.     } else {
  220.         cmd_error(side, "Already at a resupply point!");
  221.     }
  222.     } else {
  223.     cmd_error(side, "No resupply point in range!");
  224.     }
  225. }
  226.  
  227. /* Set unit to attempt to follow a coast.  Needs a starting direction, */
  228. /* which can be computed from a position. */
  229.  
  230. x_coast(side)
  231. Side *side;
  232. {
  233.     int dir;
  234.  
  235.     if (grok_position(side)) {
  236.     if (side->curx != side->reqposx || side->cury != side->reqposy) {
  237.         dir = find_dir(side->reqposx - side->curx,
  238.                side->reqposy - side->cury);
  239.         if (side->teach) {
  240.         cache_edge(side, dir, side->reqvalue2);
  241.         } else {
  242.         order_edge(side->requnit, dir, side->reqvalue2);
  243.         side->info_change = TRUE;
  244.         }
  245.         restore_cur(side);
  246.     } else {
  247.         cmd_error(side, "No particular direction at own hex??");
  248.     }
  249.     } else {
  250.     request_input(side, side->requnit, x_coast);
  251.     }
  252. }
  253.  
  254. /* The command proper just sets up the interaction. */
  255.  
  256. do_coast(side, unit, n)
  257. Side *side;
  258. Unit *unit;
  259. int n;
  260. {
  261.     ask_position(side, "Move in which direction?");
  262.     request_input(side, unit, x_coast);
  263.     side->reqposx = side->curx;  side->reqposy = side->cury;
  264.     side->reqvalue2 = n;
  265. }
  266.  
  267. /* Set orders to follow a leader unit. */
  268.  
  269. x_follow(side)
  270. Side *side;
  271. {
  272.     Unit *leader;
  273.  
  274.     if (grok_position(side)) {
  275.     if ((leader = unit_at(side->reqposx, side->reqposy)) != NULL &&
  276.         leader->side == side) {
  277.         if (leader != side->requnit) {
  278.         if (side->teach) {
  279.             cache_follow(side, leader, side->reqvalue2);
  280.         } else {
  281.             order_follow(side->requnit, leader, side->reqvalue2);
  282.             side->info_change = TRUE;
  283.         }
  284.         } else {
  285.         cmd_error(side, "Unit can't follow itself!");
  286.         }
  287.     } else {
  288.         cmd_error(side, "No unit to follow!");
  289.     }
  290.     restore_cur(side);
  291.     } else {
  292.     request_input(side, side->requnit, x_follow);
  293.     }
  294. }
  295.  
  296. /* The command proper. */
  297.  
  298. do_follow(side, unit, n)
  299. Side *side;
  300. Unit *unit;
  301. int n;
  302. {
  303.     ask_position(side, "Which unit to follow?");
  304.     request_input(side, unit, x_follow);
  305.     side->reqposx = side->curx;  side->reqposy = side->cury;
  306.     side->reqvalue2 = n;
  307. }
  308.  
  309. /* Patrolling goes back and forth between two points.  First point is the */
  310. /* current position. */
  311.  
  312. x_patrol(side)
  313. Side *side;
  314. {
  315.     if (grok_position(side)) {
  316.     if (side->teach) {
  317.         cache_patrol(side, side->sounit->x, side->sounit->y,
  318.              side->reqposx, side->reqposy, side->reqvalue2);
  319.     } else {
  320.         order_patrol(side->requnit, side->requnit->x, side->requnit->y,
  321.              side->reqposx, side->reqposy, side->reqvalue2);
  322.         side->info_change = TRUE;
  323.     }
  324.     restore_cur(side);
  325.     } else {
  326.     request_input(side, side->requnit, x_patrol);
  327.     }
  328. }
  329.  
  330. /* The command proper. */
  331.  
  332. do_patrol(side, unit, n)
  333. Side *side;
  334. Unit *unit;
  335. int n;
  336. {
  337.     ask_position(side, "What other endpoint for patrol?");
  338.     request_input(side, unit, x_patrol);
  339.     side->reqposx = side->curx;  side->reqposy = side->cury;
  340.     side->reqvalue2 = n;
  341. }
  342.  
  343. /* Delay a unit's move until a later time.  The set flag will be recognized */
  344. /* by the movement loops, when deciding which unit to move next. */
  345.  
  346. do_delay(side, unit, n)
  347. Side *side;
  348. Unit *unit;
  349. int n;
  350. {
  351.     delaymove = TRUE;
  352.     notify(side, "Delaying moving %s.", unit_handle(side, unit));
  353. }
  354.  
  355. /* Get rid of unit.  Some units cannot be disbanded, but if they can, the */
  356. /* resources go to a transport if one is there.  Disbanding a transport */
  357. /* also disbands all the occupants - oh well. */
  358.  
  359. do_disband(side, unit, n)
  360. Side *side;
  361. Unit *unit;
  362. int n;
  363. {
  364.     int u = unit->type;
  365.  
  366.     if (utypes[u].disband || Build) {
  367.     notify(side, "%s goes home.", unit_handle(side, unit));
  368.     if (unit->transport != NULL) recycle_unit(unit, unit->transport);
  369.     kill_unit(unit, DISBAND);
  370.     make_current(side, unit_at(side->curx, side->cury));
  371.     } else {
  372.     cmd_error(side, "You can't just get rid of the %s!", utypes[u].name);
  373.     }
  374. }
  375.  
  376. /* Reclaim both the unit's supplies and anything used in its making, but */
  377. /* only let a maker of the unit reclaim its ingredients. */
  378.  
  379. recycle_unit(unit, unit2)
  380. Unit *unit, *unit2;
  381. {
  382.     int u = unit->type, u2 = unit2->type, r, scrap;
  383.  
  384.     for_all_resource_types(r) {
  385.     transfer_supply(unit, unit2, r, unit->supply[r]);
  386.     if (could_make(u2, u) > 0) {
  387.         scrap = utypes[u].tomake[r];
  388.         unit2->supply[r] += (scrap * period.efficiency) / 100;
  389.     }
  390.     }
  391. }
  392.  
  393. /* Give a unit to another side (possibly to neutrals).  Units that won't */
  394. /* change their sides when captured won't change voluntarily either. */
  395.  
  396. do_give_unit(side, unit, n)
  397. Side *side;
  398. Unit *unit;
  399. int n;
  400. {
  401.     int u = unit->type;
  402.  
  403.     if (utypes[u].changeside || Build) {
  404.     unit_changes_side(unit, side_n(n), CAPTURE, PRISONER);
  405.     all_see_hex(unit->x, unit->y);
  406.     side->info_change = TRUE;
  407.     } else {
  408.     cmd_error(side, "You can't just give away the %s!", utypes[u].name);
  409.     }
  410. }
  411.  
  412. /* Marking is for the purpose of rearranging units within a hex. */
  413.  
  414. do_mark_unit(side, unit, n)
  415. Side *side;
  416. Unit *unit;
  417. int n;
  418. {
  419.     side->markunit = unit;
  420.     notify(side, "%s has been marked.", unit_handle(side, unit));
  421. }
  422.  
  423. /* This is a clever (if I do say so myself) command to examine all occupants */
  424. /* and suboccupants, in a preorder fashion. */
  425.  
  426. do_occupant(side, unit, n)
  427. Side *side;
  428. Unit *unit;
  429. int n;
  430. {
  431.     Unit *nextup;
  432.  
  433.     switch (side->mode) {
  434.     case MOVE:
  435.     cmd_error(side, "Can only look at occupants when in survey mode!");
  436.     break;
  437.     case SURVEY:
  438.     if (unit->occupant != NULL) {
  439.         make_current(side, unit->occupant);
  440.     } else if (unit->nexthere != NULL) {
  441.         make_current(side, unit->nexthere);
  442.     } else {
  443.         nextup = unit->transport;
  444.         if (nextup != NULL) {
  445.         while (nextup->transport != NULL && nextup->nexthere == NULL) {
  446.             nextup = nextup->transport;
  447.         }
  448.         if (nextup->nexthere != NULL)
  449.             make_current(side, nextup->nexthere);
  450.         if (nextup->transport == NULL)
  451.             make_current(side, nextup);
  452.         }
  453.     }
  454.     break;
  455.     default:
  456.     case_panic(side->mode, "mode");
  457.     break;
  458.     }
  459. }
  460.  
  461. /* This can actually do general rearrangement, but defaults to putting the */
  462. /* unit on the first available transport in the hex.  */
  463. /* What about trying to embark a unit on itself or on its previous transp? */
  464.  
  465. do_embark(side, unit, n)
  466. Side *side;
  467. Unit *unit;
  468. int n;
  469. {
  470.     Unit *mainunit = unit_at(side->curx, side->cury);
  471.     Unit *transport = NULL;
  472.  
  473.     if (mainunit != unit) {
  474.     if (side->markunit == NULL ||
  475.         side->markunit->x != unit->x || side->markunit->y != unit->y) {
  476.         for_all_occupants(mainunit, transport) {
  477.         if (can_carry(transport, unit)) break;
  478.         }
  479.     } else {
  480.         if (can_carry(side->markunit, unit))
  481.             transport = side->markunit;
  482.     }
  483.     if (transport != NULL) {
  484.         leave_hex(unit);
  485.         occupy_unit(unit, transport);
  486.         side->info_change = TRUE;
  487.     } else {
  488.         cmd_error(side, "No plausible transport!");
  489.     }
  490.     } else {
  491.     cmd_error(side, "Nothing for this unit to get into!");
  492.     }
  493. }
  494.  
  495. /* Give supplies to a transport.  The argument tells how many to give. */
  496.  
  497. do_give(side, unit, n)
  498. Side *side;
  499. Unit *unit;
  500. int n;
  501. {
  502.     bool something = FALSE;
  503.     int u = unit->type, m, r, gift, actual;
  504.     Unit *main = unit->transport;
  505.  
  506.     if (main != NULL) {
  507.     sprintf(spbuf, "");
  508.     m = main->type;
  509.     for_all_resource_types(r) {
  510.         gift = (n < 0 ? utypes[m].storage[r] - main->supply[r] : n);
  511.         if (gift > 0) {
  512.         something = TRUE;
  513.         /* Be stingy if we're low */
  514.         if (2 * unit->supply[r] < utypes[u].storage[r])
  515.             gift = max(1, gift/2);
  516.         actual = transfer_supply(unit, main, r, gift);
  517.         sprintf(tmpbuf, " %d %s", actual, rtypes[r].name);
  518.         strcat(spbuf, tmpbuf);
  519.         }
  520.     }
  521.     if (something) {
  522.         notify(side, "%s gave%s.", unit_handle(side, unit), spbuf);
  523.         side->info_change = TRUE;
  524.     } else {
  525.         notify(side, "%s gave nothing.", unit_handle(side, unit));
  526.     }
  527.     } else {
  528.     cmd_error(side, "Can't transfer supplies here!");
  529.     }
  530. }
  531.  
  532. /* Take supplies from transport.  Both the transport must have something */
  533. /* left. */
  534.  
  535. do_take(side, unit, n)
  536. Side *side;
  537. Unit *unit;
  538. int n;
  539. {
  540.     bool something = FALSE;
  541.     int u = unit->type, m, r, need, actual;
  542.     Unit *main = unit->transport;
  543.  
  544.     if (main != NULL) {
  545.     sprintf(spbuf, "");
  546.     m = main->type;
  547.     for_all_resource_types(r) {
  548.         need = (n < 0 ? utypes[u].storage[r] - unit->supply[r] : n);
  549.         if (need > 0) {
  550.         something = TRUE;
  551.         /* Be stingy if we're low */
  552.         if (2 * main->supply[r] < utypes[m].storage[r])
  553.             need = max(1, need/2);
  554.         actual = transfer_supply(main, unit, r, need);
  555.         sprintf(tmpbuf, " %d %s", actual, rtypes[r].name);
  556.         strcat(spbuf, tmpbuf);
  557.         }
  558.     }
  559.     if (something) {
  560.         notify(side, "%s got%s.", unit_handle(side, unit), spbuf);
  561.         side->info_change = TRUE;
  562.     } else {
  563.         notify(side, "%s needed nothing.", unit_handle(side, unit));
  564.     }
  565.     } else {
  566.     cmd_error(side, "Can't transfer supplies here!");
  567.     }
  568. }
  569.  
  570. /* Take the current player out of the game while letting everybody else */
  571. /* continue on. */
  572.  
  573. x_resign(side)
  574. Side *side;
  575. {
  576.     if (grok_bool(side)) resign_game(side, side->reqoside);
  577. }
  578.  
  579. do_resign(side, n)
  580. Side *side;
  581. int n;
  582. {
  583.     ask_bool(side, "Do you really want to give up?", FALSE);
  584.     request_input(side, NULL, x_resign);
  585.     side->reqoside = side_n(n);
  586. }
  587.  
  588. /* Unconditional resignation - usable by everybody. */
  589.  
  590. resign_game(side, side2)
  591. Side *side, *side2;
  592. {
  593.     notify_all("Those wimpy %s have given up!", plural_form(side->name));
  594.     if (side2 != NULL) {
  595.     notify_all("... and they gave all their stuff to the %s!",
  596.            plural_form(side2->name));
  597.     }
  598.     side_loses(side, side2);
  599. }
  600.  
  601. /* Leave quickly when the boss walks by.  One person can kill a multi-player */
  602. /* game, which isn't too great, but the alternatives are complicated. */
  603. /* The stats file will be left behind, to foment argument about who would */
  604. /* have won... This routine also includes a trapdoor for freezing/unfreezing */
  605. /* machine players when building - mode display will invert to confirm this. */
  606.  
  607. x_exit(side)
  608. Side *side;
  609. {
  610.     Unit *unit;
  611.  
  612.     if (grok_bool(side)) {
  613.     close_displays();
  614.     printf("\nThe outcome remains undecided");
  615.     if (numhumans == 1 && side->humanp) {
  616.         printf(", but you're probably the loser!\n\n", side->host);
  617.     } else {
  618.         printf("...\n\n");
  619.     }
  620.     /* Need to kill off all units to finish up statistics */
  621.     for_all_units(unit) if (alive(unit)) kill_unit(unit, ENDOFWORLD);
  622.     print_statistics();
  623.     exit(0);
  624.     }
  625.     if (Build) {
  626.     Freeze = !Freeze;
  627.     show_timemode(side);
  628.     }
  629. }
  630.  
  631. do_exit(side, n)
  632. Side *side;
  633. int n;
  634. {
  635.     ask_bool(side, "Do you REALLY want to end the game for EVERYBODY?",
  636.          FALSE);
  637.     request_input(side, NULL, x_exit);
  638. }
  639.  
  640. /* Stuff game state into a file.  By default, it goes into the current */
  641. /* directory.  If building a scenario, will ask about each section, values */
  642. /* of globals, and dest file before actually writing anything. */
  643. /* No capability to write out period at present... */
  644.  
  645. x_save_1(side)
  646. Side *side;
  647. {
  648.     char *sects, *fname;
  649.     int sdetail = 1, udetail = 1;
  650.  
  651.     if ((sects = grok_string(side)) != NULL) {
  652.     fname = "random.scn";
  653.     sprintf(spbuf, "------");
  654.     if (iindex('v', sects) >= 0) spbuf[0] = '+';
  655.     if (iindex('p', sects) >= 0) spbuf[1] = '+';
  656.     if (iindex('m', sects) >= 0) spbuf[2] = '+';
  657.     if (iindex('g', sects) >= 0) spbuf[3] = '+';
  658.     if (iindex('s', sects) >= 0) spbuf[4] = '+';
  659.     if (iindex('u', sects) >= 0) spbuf[5] = '+';
  660.     if (iindex('s', sects) >= 0) {
  661.         sdetail = 1;
  662.         if (isdigit(sects[iindex('s', sects)+1]))
  663.         sdetail = sects[iindex('s', sects)+1] - '0';
  664.     }
  665.     if (iindex('u', sects) >= 0) {
  666.         udetail = 1;
  667.         if (isdigit(sects[iindex('u', sects)+1]))
  668.         udetail = sects[iindex('u', sects)+1] - '0';
  669.     }
  670.     notify(side, "Mapfile with sections %s will be saved to \"%s\" ...",
  671.            spbuf, fname);
  672.     if (write_scenario(fname, spbuf, sdetail, udetail)) {
  673.         notify(side, "Done writing to \"%s\".", fname);
  674.     } else {
  675.         cmd_error(side, "Can't open file \"%s\"!", fname);
  676.     }
  677.     } else {
  678.     request_input(side, NULL, x_save_1);
  679.     }
  680. }
  681.  
  682. /* Make a header appropriate to a save file, write the file, and leave. */
  683.  
  684. x_save_2(side)
  685. Side *side;
  686. {
  687.     if (grok_bool(side)) {
  688.     notify_all("Game will be saved to \"%s\" ...", SAVEFILE);
  689.     if (write_savefile(SAVEFILE)) {
  690.         close_displays();
  691.         exit(0);
  692.     } else {
  693.         cmd_error(side, "Can't open file \"%s\"!", SAVEFILE);
  694.     }
  695.     }
  696. }
  697.  
  698. /* The command proper just sets up different handlers, depending on */
  699. /* whether we're building (and therefore saving a scenario/fragment), or */
  700. /* saving as much game state as possible, for resumption later. */
  701.  
  702. do_save(side, n)
  703. Side *side;
  704. int n;
  705. {
  706.     if (Build) {
  707.     ask_string(side, "Sections to write?", "ms1u1");
  708.     request_input(side, NULL, x_save_1);
  709.     } else {
  710.     ask_bool(side, "You really want to save?", FALSE);
  711.     request_input(side, NULL, x_save_2);
  712.     }
  713. }
  714.  
  715. /* Redraw everything using the same code as when windows need a redraw. */
  716.  
  717. do_redraw(side, n)
  718. Side *side;
  719. int n;
  720. {
  721.     redraw(side);
  722. }
  723.  
  724. /* Flicker on the current position, in case it's not easily visible. */
  725.  
  726. do_flash(side, n)
  727. Side *side;
  728. int n;
  729. {
  730.     int sx, sy;
  731.  
  732.     xform(side, unwrap(side, side->curx), side->cury, &sx, &sy);
  733.     flash_position(side, sx, sy, 1000);
  734. }
  735.  
  736. /* Name or rename the current unit or a given side.  We make a copy of the */
  737. /* string after it's been successfully read, just in case. */
  738.  
  739. x_name(side)
  740. Side *side;
  741. {
  742.     char *name;
  743.     Side *side2;
  744.  
  745.     if ((name = grok_string(side)) == NULL) {
  746.     request_input(side, side->requnit, x_name);
  747.     } else if (strlen(name) == 0) {
  748.     notify(side, "Name not changed.");
  749.     } else if (side->requnit != NULL) {
  750.     side->requnit->name = copy_string(name);
  751.     side->info_change = TRUE;
  752.     } else if (side->reqoside != NULL) {
  753.     side->reqoside->name = copy_string(name);
  754.     for_all_sides(side2) show_all_sides(side2);
  755.     } else {
  756.     cmd_error(side, "Nothing to name!");
  757.     }
  758. }
  759.  
  760. /* The command proper decides between unit and side naming. */
  761.  
  762. do_name(side, n)
  763. Side *side;
  764. int n;
  765. {
  766.     if (side->curunit != NULL) {
  767.     ask_string(side, "New name for unit:", side->curunit->name);
  768.     } else {
  769.     ask_string(side, "New name for yourself:", side->name);
  770.     side->reqoside = side;
  771.     }
  772.     request_input(side, side->curunit, x_name);
  773. }
  774.  
  775. /* Designate the current location as the center of action and sort all */
  776. /* of our own units relative to it. */
  777.  
  778. do_center(side, n)
  779. Side *side;
  780. int n;
  781. {
  782.     side->cx = side->curx;  side->cy = side->cury;
  783.     sort_units(TRUE);
  784.     notify(side, "Units reordered.");
  785. }
  786.  
  787. /* Hook command to set miscellaneous options.  Can't do from command line */
  788. /* because each display may want different behavior.  This routine can */
  789. /* change the display dramatically, but it should only redraw if a change */
  790. /* has actually been made. */
  791.  
  792. /* Conversion to machine player is irreversible, so we confirm it first. */
  793.  
  794. x_options_2(side)
  795. Side *side;
  796. {
  797.     if (grok_bool(side)) {
  798.     side->humanp = !side->humanp;
  799.     numhumans--;
  800.     init_sighandlers();
  801.     }
  802. }
  803.  
  804. x_options(side)
  805. Side *side;
  806. {
  807.     int n = side->reqvalue2;
  808.     char opt;
  809.  
  810.     if ((opt = grok_char(side)) != '\0') {
  811.     switch (opt) {
  812.     case '?':
  813.         notify(side, "Change (D)isplay Mode, (G)raph, Win (H)eight,");
  814.         notify(side, "(I)nverse Video, (M)onochrome, (N)otice Buffer");
  815.         notify(side, "(R)obot, Win (W)idth");
  816.         break;
  817.     case 'd':
  818.         remap = TRUE;
  819.         side->showmode = (side->showmode + 1) % 4;
  820.         break;
  821.     case 'g':
  822.         reinfo = TRUE;
  823.         side->graphical = !side->graphical;
  824.         break;
  825.     case 'h':
  826.         if (n < 5 || n > world.height) {
  827.         cmd_error(side, "Bad height %d!", n);
  828.         } else {
  829.         if (n != side->vh) reconfig = TRUE;
  830.         side->vh = n;
  831.         }
  832.         break;
  833.     case 'i':
  834.         if (side->monochrome) {
  835.         reconfig = TRUE;
  836.         side->bonw = !side->bonw;
  837.         } else {
  838.         cmd_error(side, "Inverse video is only for monochrome!");
  839.         }
  840.         break;
  841.     case 'm':
  842.         reconfig = TRUE;
  843.         side->monochrome = !side->monochrome;
  844.         side->bonw = FALSE;
  845.         break;
  846.     case 'n':
  847.         if (n < 1 || n > MAXNOTES) {
  848.         cmd_error(side, "Bad number of notes %d!", n);
  849.         } else {
  850.         if (n != side->nh) reconfig = TRUE;
  851.         side->nh = n;
  852.         }
  853.         break;
  854.     case 'r':    
  855.         if (side->mode == MOVE) {
  856.         ask_bool(side,
  857.              "Do you really want to become a machine?", FALSE);
  858.         request_input(side, NULL, x_options_2);
  859.         return;
  860.         } else {
  861.         cmd_error(side, "Must be in move mode!");
  862.         }
  863.         break;
  864.     case 'w':
  865.         if (n < 5 || n > world.width || n > BUFSIZE) {
  866.         cmd_error(side, "Bad width %d!", n);
  867.         } else {
  868.         if (n != side->vw) reconfig = TRUE;
  869.         side->vw = n;
  870.         }
  871.         break;
  872.     case 'I':
  873.         invert_whole_map(side);
  874.         break;
  875.     default:
  876.         cmd_error(side, "unrecognized option '%c'", opt);
  877.         break;
  878.     }
  879.     if (remap) {
  880.         undraw_box(side);
  881.         show_map(side);
  882.     }
  883.     if (reinfo) side->info_change = TRUE;
  884.     if (reconfig) reconfigure_display(side);
  885.     } else {
  886.     request_input(side, NULL, x_options);
  887.     }
  888. }
  889.  
  890. /* The command proper. */
  891.  
  892. do_options(side, n)
  893. Side *side;
  894. int n;
  895. {
  896.     reinfo = remap = reconfig = FALSE;
  897.     ask_char(side, "Options:", "dghimnrw");
  898.     request_input(side, NULL, x_options);
  899.     side->reqvalue2 = n;
  900. }
  901.  
  902. /* Set standing orders for a unit of a given type that enters a given city. */
  903. /* Space for standing orders is dynamically allocated the first time we */
  904. /* request some orders. */
  905.  
  906. x_standing_1(side)
  907. Side *side;
  908. {
  909.     int type;
  910.  
  911.     if ((type = grok_unit_type(side)) >= 0) {
  912.     if (type != NOTHING) get_standing_order(side, type);
  913.     } else {
  914.     request_input(side, side->requnit, x_standing_1);
  915.     } 
  916. }
  917.  
  918. /* The command proper starts the ball rolling by prompting for the type */
  919. /* of unit that will get standing orders.  Of course, if a unit is not of */
  920. /* a type that has occupants, standing orders are pretty useless.  Also, */
  921. /* if only one type of occupant is possible, then no need to ask. */
  922.  
  923. do_standing(side, unit, n)
  924. Side *side;
  925. Unit *unit;
  926. int n;
  927. {
  928.     int u;
  929.  
  930.     u = ask_unit_type(side, "Type of occupant to get standing orders",
  931.               utypes[unit->type].capacity);
  932.     if (u < 0) {
  933.     show_standing_orders(side, unit);
  934.     request_input(side, unit, x_standing_1);
  935.     side->sounit = unit;
  936.     } else if (u == NOTHING) {
  937.     cmd_error(side, "This unit never has occupants to give orders to!");
  938.     } else {
  939.     show_standing_orders(side, unit);
  940.     get_standing_order(side, u);
  941.     }
  942. }
  943.  
  944. /* A standing order is acquired by snarfing the next order and saving it */
  945. /* rather than applying it to some unit. */
  946.  
  947. get_standing_order(side, type)
  948. Side *side;
  949. int type;
  950. {
  951.     int i;
  952.  
  953.     if (side->requnit->standing == NULL) {
  954.     side->requnit->standing =
  955.         (StandingOrder *) malloc(sizeof(StandingOrder));
  956.     for( i=0; i<MAXUTYPES; i++)
  957.         side->requnit->standing->orders[i] = NULL;
  958.     }
  959.     side->teach = TRUE;
  960.     side->soutype = type;
  961.     side->tmporder = (Order *) malloc(sizeof(Order));
  962.     notify(side, "Next input order will become the standing order.");
  963.     show_timemode(side);
  964.     request_command(side);
  965. }
  966.  
  967. /* Survey mode allows player to look around (and change things) by moving */
  968. /* cursor.  The same command toggles in and out, so need a case statement. */
  969. /* Players waiting their turn will be in survey mode, but can't get out. */
  970.  
  971. do_survey_mode(side, n)
  972. Side *side;
  973. int n;
  974. {
  975.     switch (side->mode) {
  976.     case MOVE:
  977.     survey_mode(side);
  978.     break;
  979.     case SURVEY:
  980.     if (side == curside) {
  981.         move_mode(side);
  982.     } else {
  983.         cmd_error(side, "Not your turn yet!");
  984.     }
  985.     break;
  986.     default:
  987.     case_panic("mode", side->mode);
  988.     }
  989. }
  990.  
  991. /* Change what a unit is producing. */
  992.  
  993. do_product(side, unit, n)
  994. Side *side;
  995. Unit *unit;
  996. int n;
  997. {
  998.     if (!global.setproduct) {
  999.     cmd_error(side, "No construction changes allowed in this game!");
  1000.     } else {
  1001.     if (!can_produce(unit)) {
  1002.         cmd_error(side, "This unit can't build anything!");
  1003.     } else {
  1004.         if (!utypes[unit->type].maker) {
  1005.         wake_unit(unit, FALSE);
  1006.         }
  1007.         request_new_product(unit);
  1008.     }
  1009.     }
  1010. }
  1011.  
  1012. /* Set a unit to not produce anything (yes, this really is useful). */
  1013.  
  1014. do_idle(side, unit, n)
  1015. Side *side;
  1016. Unit *unit;
  1017. int n;
  1018. {
  1019.     if (!global.setproduct) {
  1020.     cmd_error(side, "No production changes allowed in this scenario!");
  1021.     } else {
  1022.     set_product(unit, NOTHING);
  1023.     unit->schedule = n;
  1024.     show_info(side);
  1025.     }
  1026. }
  1027.  
  1028. /* Send a short (1 line) message to another player.  Some messages are */
  1029. /* recognized specially, causing various actions. */
  1030.  
  1031. x_message(side)
  1032. Side *side;
  1033. {
  1034.     char *msg;
  1035.     Side *side3;
  1036.  
  1037.     if ((msg = grok_string(side)) != NULL) {
  1038.     if (side->reqoside == NULL) {
  1039.         if (msg != NULL && strlen(msg) > 0) {
  1040.         notify_all("The %s announce: %s",
  1041.                plural_form(side->name), msg);
  1042.         }
  1043.     } else if (strcmp(msg, "briefing") == 0) {
  1044.         notify(side->reqoside, "Receiving a briefing from the %s...",
  1045.            plural_form(side->name));
  1046.         reveal_side(side, side->reqoside, 100);
  1047.         notify(side, "You just briefed the %s on your position.",
  1048.            plural_form(side->reqoside->name));
  1049.     } else if (strcmp(msg, "alliance") == 0) {
  1050.         notify(side, "You propose a formal alliance with the %s.",
  1051.            plural_form(side->reqoside->name));
  1052.         side->attitude[side_number(side->reqoside)] = ALLY;
  1053.         if (side->reqoside->attitude[side_number(side)] >= ALLY) {
  1054.         declare_alliance(side, side->reqoside);
  1055.         for_all_sides(side3) redraw(side3);
  1056.         } else {
  1057.         notify(side->reqoside, "The %s propose a formal alliance.",
  1058.                plural_form(side->name));
  1059.         }
  1060.     } else if (strcmp(msg, "neutral") == 0) {
  1061.         notify(side, "You propose neutrality with the %s.",
  1062.            plural_form(side->reqoside->name));
  1063.         side->attitude[side_number(side->reqoside)] = NEUTRAL;
  1064.         if (side->reqoside->attitude[side_number(side)] == NEUTRAL) {
  1065.         declare_neutrality(side, side->reqoside);
  1066.         for_all_sides(side3) redraw(side3);
  1067.         } else {
  1068.         notify(side->reqoside, "The %s propose neutrality.",
  1069.                plural_form(side->name));
  1070.         }
  1071.     } else if (strcmp(msg, "war") == 0) {
  1072.         notify(side, "You declare war on the %s!",
  1073.            plural_form(side->reqoside->name));
  1074.         declare_war(side, side->reqoside);
  1075.         for_all_sides(side3) redraw(side3);
  1076.     } else if (strlen(msg) > 0) {
  1077.         notify(side->reqoside, "The %s say to you: %s",
  1078.            plural_form(side->name), msg);
  1079.     } else {
  1080.         notify(side, "You keep your mouth shut.");
  1081.     }
  1082.     } else {
  1083.     request_input(side, NULL, x_message);
  1084.     }
  1085. }
  1086.  
  1087. /* The command proper. */
  1088.  
  1089. do_message(side, n)
  1090. Side *side;
  1091. int n;
  1092. {
  1093.     char prompt[BUFSIZE];
  1094.     Side *side2;
  1095.  
  1096.     side2 = side_n(n);
  1097.     side->reqoside = side2;
  1098.     if (side != side2) {
  1099.     if (side2) {
  1100.         sprintf(prompt, "Say to the %s: ", plural_form(side2->name));
  1101.     } else {
  1102.         sprintf(prompt, "Broadcast: ");
  1103.     }
  1104.     ask_string(side, prompt, NULL);
  1105.     request_input(side, NULL, x_message);
  1106.     } else {
  1107.     cmd_error(side, "You mumble to yourself.");
  1108.     }
  1109. }
  1110.  
  1111. /* Add a new player to the game. */
  1112. /* Should use arg to decide whether to convert machine player (or just */
  1113. /* use if available?)  Also needs to decide if new player is human and */
  1114. /* which host to open, then go through side's startup seq and open disp. */
  1115. /* Issues of cached values (?) and war/alliance setup and uses of numsides. */
  1116.  
  1117. do_add_player(side, n)
  1118. Side *side;
  1119. int n;
  1120. {
  1121.     notify(side, "Sorry, can't add new players yet!");
  1122. }
  1123.  
  1124. /* Command to display the program version.  Looks wired in, but of course */
  1125. /* this is not something that we want to be easily changeable! */
  1126. /* This will also show data about other sides. */
  1127.  
  1128. do_version(side, n)
  1129. Side *side;
  1130. int n;
  1131. {
  1132.    notify(side, " ");
  1133.    notify(side,
  1134.       "XCONQ version %s", version);
  1135.    notify(side,
  1136.       "(c) Copyright 1987, 1988  Stanley T. Shebs, University of Utah");
  1137.    notify(side, " ");
  1138.    if (Debug || Build) reveal_side(NULL, side, 100);
  1139. }
  1140.  
  1141. /* Create any unit anywhere.  It gets the usual initial supply, and its */
  1142. /* current side is also its true side (i.e. it will never revolt). */
  1143.  
  1144. x_unit(side)
  1145. Side *side;
  1146. {
  1147.     int u;
  1148.     Unit *unit;
  1149.  
  1150.     if ((u = grok_unit_type(side)) >= 0) {
  1151.     if (u != NOTHING) {
  1152.         unit = create_unit(u, NULL);
  1153.         occupy_hex(unit, side->curx, side->cury);
  1154.         init_supply(unit);
  1155.         unit_changes_side(unit, side->reqoside, -1, -1);
  1156.         unit->trueside = unit->side;
  1157.         make_current(side, unit);
  1158.         all_see_hex(side->curx, side->cury);
  1159.     }
  1160.     } else {
  1161.     ask_unit_type(side, "Type of unit to create?", NULL);
  1162.     request_input(side, NULL, x_unit);
  1163.     }
  1164. }
  1165.  
  1166. /* The command function proper, which only works in Build mode. */
  1167.  
  1168. do_unit(side, n)
  1169. Side *side;
  1170. int n;
  1171. {
  1172.     if (Build) {
  1173.     if (unit_at(side->curx, side->cury) == NULL) {
  1174.         ask_unit_type(side, "Type of unit to create?", NULL);
  1175.         side->reqoside = side_n(n);
  1176.         request_input(side, NULL, x_unit);
  1177.     } else {
  1178.         cmd_error(side, "Unit already here!");
  1179.     }
  1180.     } else {
  1181.     cmd_error(side, "Not building a mapfile!");
  1182.     }
  1183. }
  1184.  
  1185. /* Terrain editing alters a hexagonal area of given radius.  If only one */
  1186. /* hex changed (the default), just update that alone; otherwise, go ahead */
  1187. /* and redraw everything. */
  1188.  
  1189. /* The command itself just sets up what will be drawn. */
  1190.  
  1191. do_terrain(side, terr, n)
  1192. Side *side;
  1193. int terr, n;
  1194. {
  1195.     tmpterr = terr;
  1196.     tmpdist = min(abs(n), world.width);
  1197.     tmparea = (n >= 0);
  1198.     notify(side, "Will now paint %d hex %s of %s.",
  1199.        tmpdist, (tmparea ? "radius areas" : "bars"), ttypes[tmpterr].name);
  1200. }
  1201.  
  1202. /* Function to change just one hex and to echo that change. */
  1203. /* Don't need to make it show instantly, can wait. */
  1204.  
  1205. set_one_hex(x, y)
  1206. int x, y;
  1207. {
  1208.     set_terrain_at(x, y, tmpterr);
  1209.     if (see_exact(tmpside, x, y))
  1210.         draw_hex(tmpside, x, y, FALSE);
  1211. }
  1212.  
  1213. /* Painting operation is activated by the "sit" command. */
  1214.  
  1215. paint_terrain(side)
  1216. Side *side;
  1217. {
  1218.     int i;
  1219.  
  1220.     tmpside = side;
  1221.     if (tmparea) {
  1222.     apply_to_area(side->curx, side->cury, tmpdist, set_one_hex);
  1223.     } else {
  1224.     for (i = 0; i < tmpdist; ++i)
  1225.         set_one_hex(wrap(side->curx + i), side->cury);
  1226.     }
  1227. }
  1228.  
  1229. /* Generic command error routine - beeps display etc. */
  1230.  
  1231. /*VARARGS*/
  1232. cmd_error(side, control, a1, a2, a3, a4, a5, a6)
  1233. Side *side;
  1234. char *control, *a1, *a2, *a3, *a4, *a5, *a6;
  1235. {
  1236.     notify(side, control, a1, a2, a3, a4, a5, a6);
  1237.     if (active_display(side)) beep(side);
  1238. }
  1239.